Fondamentaux “ base”

Noms et Valeurs

Affectation

x <- c(1, 2, 3)

“Crée un objet nommé ‘x’, contenant les valeurs 1, 2 et 3” ou plus précisément :

  • Crée un objet de type vecteur c(1, 2, 3).

  • Associe cet objet à un nom x.

Affectation

x <- c(1, 2, 3)
y <- x
lobstr::obj_addr(x)
#> [1] "0x55d05f32ade8"
lobstr::obj_addr(y)
#> [1] "0x55d05f32ade8"

y n’est pas une copie de x.
x et y sont des références à l’objet de type vecteur c(1, 2, 3).

Noms Non-syntaxique

dispose d’un ensemble de règles pour les noms utilisables :

  • Contient uniquement des lettres (ASCII, mais pas uniquement), des chiffres, . et _.

  • Ne peut pas débuter par des chiffres ou _.

  • Ne peut pas être un “nom réservé” (?Reserved).

Noms Non-syntaxique

_abc <- 1
#> Error: <text>:1:1: unexpected input
#> 1: _
#>     ^
TRUE <- "false"
#> Error in TRUE <- "false": invalid (do_set) left-hand side to assignment
`_abc` <- 1
`+` <- 1

Exercices

  1. Expliquer les relations entre a, b, d, et e.

    a <- 1:10
    b <- a
    b -> e
    e <- d <- 1:10
  2. Que donne le code suivant pour importer un “fichier” csv ? Quel argument faudrait-il utiliser pour avoir les noms des colonnes tels-qu’ils sont ?

    read.csv(
      header = TRUE, 
      text = "1ere_colonne,deuxième_colonne,troisième colonne\n1,2,3"
    )
  3. Les fonctions read.*() utilisent make.names() ? Quels sont les règles de conversions utilisées ?

Modification sur Copie (“Copy-on-modify”)

x <- c(1, 2, 3)
y <- x

y[3] <- 4
x
#> [1] 1 2 3
y
#> [1] 1 2 4

La modification de y n’a pas modifié x.
crée une copie de l’objet référencé par x en modifiant la troisième valeur.
Ce nouvel objet est ensuite référencé par y.

Déréférencement et “Garbage Collection”

x <- 1:3
x <- 2:4

rm(x) # Déréférencement

gc() # Force "Garbage Collection"
#>           used (Mb) gc trigger (Mb) max used (Mb)
#> Ncells  677414 36.2    1217144 65.1  1217144 65.1
#> Vcells 1197812  9.2    8388608 64.0  2483834 19.0

Exercices

  1. À quelle ligne, une copie de a est effectuée ?

    a <- c(1, 5, 3, 2)
    b <- a
    b[[1]] <- 10

Fondamentaux “ base”

Les Vecteurs

Les Vecteurs

  • Booléen : TRUE et FALSE.
  • Numérique
    • Flottant (“double”)
      • Décimal 0.1234.
      • Scientifique 1.23e4.
      • Hexadécimal 0xcafe.
      • Valeurs particulières : Inf, -Inf et NaN.
    • Entier (“integer”) : suffixe L, p.ex., 123L, 1.23e4L et 0xcafeL.
  • Chaîne de caractères : entourées par " ou '.
    Les caractères spéciaux sont échappés par \ (?Quotes).

Les Vecteurs

c() (“combine”) permet de constituer des vecteurs de longueurs supérieurs à 1.

lgl_var <- c(TRUE, FALSE)
int_var <- c(1L, 6L, 10L)
dbl_var <- c(1, 2.5, 4.5)
chr_var <- c("these are", "some strings")

Lorsque les éléments de c() sont dit atomiques, le résultat est alors de même nature.

c(c(1, 2), c(3, 4))
#> [1] 1 2 3 4

Les Vecteurs

Le type d’un vecteur peut-être déterminé via typeof().

typeof(lgl_var)
#> [1] "logical"
typeof(int_var)
#> [1] "integer"
typeof(dbl_var)
#> [1] "double"
typeof(chr_var)
#> [1] "character"

Les Vecteurs

Et sa longueur via length().

length(lgl_var)
#> [1] 2
length(int_var)
#> [1] 3
length(dbl_var)
#> [1] 3
length(chr_var)
#> [1] 2

Valeurs Manquantes

symbolise les valeurs manquantes à l’aide de NA (“not applicable”).
Un calcul impliquant NA résultera en un NA.

NA > 5
#> [1] NA
10 * NA
#> [1] NA
!NA
#> [1] NA

Valeurs Manquantes

À quelques exceptions.

NA ^ 0
#> [1] 1
NA | TRUE
#> [1] TRUE
NA & FALSE
#> [1] FALSE

Valeurs Manquantes

Détermination des valeurs manquantes d’un vecteur de façon “naïve”.

x <- c(NA, 5, NA, 10)
x == NA
#> [1] NA NA NA NA

La bonne approche pour éviter les erreurs.

is.na(x)
#> [1]  TRUE FALSE  TRUE FALSE

Valeurs Manquantes

NA est la forme “générique”, mais il existe un NA pour chacun des types :

  • Booléen : NA.
  • Numérique
    • Flottant (“double”) : NA_real_.
    • Entier (“integer”) : NA_integer_.
  • Chaîne de caractères : NA_character_.

Test et Conversion de Type

dispose de fonctions is.*() pour tester le type d’un vecteur, mais sont à utiliser avec précautions.

is.logical(), is.integer(), is.double() et is.character() effectueront bien le test demandé/attendu.

Ce qui ne sera pas nécessairement le cas de is.vector(), is.atomic() et is.numeric().

?is.numeric

is.numeric is an internal generic primitive function: you can write methods to handle specific classes of objects, see InternalMethods. It is not the same as is.double. Factors are handled by the default method, and there are methods for classes “Date”, “POSIXt” and “difftime” (all of which return false). Methods for is.numeric should only return true if the base type of the class is double or integer and values can reasonably be regarded as numeric (e.g., arithmetic on them makes sense, and comparison should be done via the base type).

Test et Conversion de Type

Un vecteur ne dispose que d’un seul type, c’est-à-dire, tous les éléments doivent avoir le même type.

Lorsque les éléments d’un vecteur sont de plusieurs types, une conversion sera appliquée selon la règle de priorité :
characterdoubleintegerlogical.

x <- c("a", 1)
typeof(x)
#> [1] "character"
str(x)
#>  chr [1:2] "a" "1"

Test et Conversion de Type

La plupart des fonctions mathématiques réalise cette conversion de type (p.ex., +, log, etc.).

x <- c(FALSE, FALSE, TRUE)
as.numeric(x)
#> [1] 0 0 1
# Nombre de "TRUE"
sum(x)
#> [1] 1
# Proportion de "TRUE"
mean(x)
#> [1] 0.3333333

Test et Conversion de Type

Il est possible de convertir explicitement un vecteur avec les fonctions as.*() : as.logical(), as.integer(), as.double() et as.character().

avertira via un avertissement d’un problème lors de la conversion.

as.integer(c("1", "1.5", "a"))
#> Warning: NAs introduced by coercion
#> [1]  1  1 NA

Exercices

  1. Déterminer le type des vecteurs suivants.

    c(1, FALSE)
    c("a", 1)
    c(TRUE, 1L)
  2. Déterminer le résultat des comparaisons suivantes.

    1 == "1"
    -1 < FALSE
    "one" < 2

    Pour quelle raison ces résultats ont été obtenu ?

  3. Pourquoi le type par défaut de NA est booléen ?

Les Attributs

Les attributs sont des meta-données stockées sont la forme de paire nom/valeur.
Chaque attribut peut être récupéré et défini individuellement via attr(), récupéré en masse via attributes() ou encore défini en masse via structure().

a <- 1:3
attr(a, "x") <- "abcdef"
attr(a, "x")
#> [1] "abcdef"
attr(a, "y") <- 4:6
str(attributes(a))
#> List of 2
#>  $ x: chr "abcdef"
#>  $ y: int [1:3] 4 5 6

Les Attributs

a <- structure(
  1:3, 
  x = "abcdef",
  y = 4:6
)
str(attributes(a))
#> List of 2
#>  $ x: chr "abcdef"
#>  $ y: int [1:3] 4 5 6

Les Attributs

Les attributs sont en général éphémères, dans le sens où ils sont perdus dans la plupart des opérations.

attributes(a[1])
#> NULL
attributes(sum(a))
#> NULL

Là encore, il y a principalement deux exceptions :

  • noms (names), un vecteur de chaîne de caractères donnant le nom de chaque élément.
  • dimension (dim), un vecteur de valeurs entières donnant les dimensions (utilisé dans la conversion des vecteurs en matrices ou “arrays”).

Les Attributs : Noms

Il existe plusieurs façons de nommer les éléments d’un vecteur.

  • Lors de la création.

    x <- c(a = 1, b = 2, c = 3)
  • Avec names() pour affecter des un vecteur de chaîne de caractères.

    x <- 1:3
    names(x) <- c("a", "b", "c")
  • Avec setNames(), pour réaliser la même tâche en une seule ligne.

    x <- setNames(1:3, c("a", "b", "c"))

Les Attributs : Dimensions

  • Les vecteurs sont de dimension NULL.

    dim(1:6)
    #> NULL
  • Les matrices sont de dimension 2.

    x <- matrix(1:6, nrow = 2, ncol = 3)
    dim(x)
    #> [1] 2 3
  • Les “arrays” sont de dimension n.

    x <- array(1:12, dim = c(2, 3, 2))
    dim(x)
    #> [1] 2 3 2

Les Attributs : Dimensions

Il est possible de modifier directement les dimensions d’un vecteur pour en modifier la “forme”.

x <- 1:6
dim(x) <- c(3, 2)
x
#>      [,1] [,2]
#> [1,]    1    4
#> [2,]    2    5
#> [3,]    3    6

Les Attributs : Dimensions

Vector Matrix Array
names() rownames(), colnames() dimnames()
length() nrow(), ncol() dim()
c() rbind(), cbind() abind::abind()
--- t() aperm()
is.null(dim(x)) is.matrix() is.array()

Les Attributs : Dimensions

str() est le meilleur moyen d’identifier la “nature” d’un objet.

str(1:3)                   # 1d vector
#>  int [1:3] 1 2 3
str(matrix(1:3, ncol = 1)) # column vector
#>  int [1:3, 1] 1 2 3
str(matrix(1:3, nrow = 1)) # row vector
#>  int [1, 1:3] 1 2 3
str(array(1:3, 3))         # "array" vector
#>  int [1:3(1d)] 1 2 3

Les Vecteurs S3

class est un autre attribut important dans , il est le fondement du système objet S3.

Un objet possédant l’attribut class devient un objet S3 qui réagira différemment d’un simple objet au regard d’une fonction dite “générique”.

Les principaux vecteurs S3 :

  • factor, permettant de définir des niveaux pour un vecteur.
  • Date, la date dans un format défini au jour près.
  • POSIXct, la date dans un format défini à la seconde près.

Les Vecteurs S3 : Les Facteurs

Un facteur est un vecteur ne pouvant contenir que des valeurs prédéfinies.
Ce type de vecteur est utilisé pour stocker des données catégorielles / discrètes en se basant sur un vecteur d’entier.

x <- factor(c("a", "b", "b", "a"))
x
#> [1] a b b a
#> Levels: a b
typeof(x)
#> [1] "integer"

Les Vecteurs S3 : Les Facteurs

Un facteur est un vecteur ne pouvant contenir que des valeurs prédéfinies.
Ce type de vecteur est utilisé pour stocker des données catégorielles / discrètes en se basant sur un vecteur d’entier.

attributes(x)
#> $levels
#> [1] "a" "b"
#> 
#> $class
#> [1] "factor"
str(x)
#>  Factor w/ 2 levels "a","b": 1 2 2 1

Les Vecteurs S3 : Les Facteurs

Les niveaux d’un facteur peuvent être connus, mais pas nécessairement observés dans les données.

sex_char <- c("m", "m", "m")
sex_factor <- factor(sex_char, levels = c("m", "f"))

Ainsi, il est possible de compter les occurrences de l’ensemble des niveaux.

table(sex_char)
#> sex_char
#> m 
#> 3
table(sex_factor)
#> sex_factor
#> m f 
#> 3 0

Les Vecteurs S3 : Les Facteurs

Les facteurs peuvent également être ordonnées et se comportent comme des facteurs “classiques”.

ordered(c("b", "b", "a", "c"), levels = c("c", "b", "a"))
#> [1] b b a c
#> Levels: c < b < a
factor( c("b", "b", "a", "c"), levels = c("c", "b", "a"), ordered = TRUE)
#> [1] b b a c
#> Levels: c < b < a

Note : Les fonctions read.*() et data.frame() convertissent automatique les vecteurs de chaîne de caractères en facteurs. Il est recommandé de désactiver ce comportant options(stringsAsFactors = FALSE) (Par défaut avec R > 4.0).

Exercices

  1. Quelle sorte d’objet renvoi table() ? Quel est son type ? Quels sont ses attributs ?

  2. Qu’arrive-t-il à un facteur lorsque les niveaux sont modifiés ?

    f1 <- factor(letters)
    levels(f1) <- rev(levels(f1))
  3. Que fait le code suivant ? De quelle façon f2 et f3 différent-ils de f1 ?

    f2 <- rev(factor(letters))
    f3 <- factor(letters, levels = rev(letters))

Les Listes

À la différence des vecteurs, les éléments d’une liste peuvent être de n’importe quel type, il n’est plus question de “cohérence de type”.

l1 <- list(
  1:3, 
  "a", 
  c(TRUE, FALSE, TRUE), 
  c(2.3, 5.9)
)
typeof(l1)
#> [1] "list"

Les Listes

À la différence des vecteurs, les éléments d’une liste peuvent être de n’importe quel type, il n’est plus question de “cohérence de type”.

str(l1)
#> List of 4
#>  $ : int [1:3] 1 2 3
#>  $ : chr "a"
#>  $ : logi [1:3] TRUE FALSE TRUE
#>  $ : num [1:2] 2.3 5.9

Les Listes

Chaque élément d’une liste, n’est en réalité qu’une référence à l’objet.

lobstr::obj_size(mtcars)
#> 7,208 B
l2 <- list(mtcars, mtcars, mtcars, mtcars)
lobstr::obj_size(l2)
#> 7,288 B

Les Listes

La levée de la contrainte de “cohérence de type” fait des listes un type particulièrement flexible et de ce fait ne permet pas d’avoir une représentation générique efficace systématiquement, comme c’est le cas pour les vecteurs.

l3 <- list(list(list(1)))
str(l3)
#> List of 1
#>  $ :List of 1
#>   ..$ :List of 1
#>   .. ..$ : num 1

Les Listes

c() permet de combiner des éléments dans le cas des listes.

l4 <- list(list(1, 2), c(3, 4))
str(l4)
#> List of 2
#>  $ :List of 2
#>   ..$ : num 1
#>   ..$ : num 2
#>  $ : num [1:2] 3 4
l5 <- c(list(1, 2), c(3, 4))
str(l5)
#> List of 4
#>  $ : num 1
#>  $ : num 2
#>  $ : num 3
#>  $ : num 4

Test et Conversion de Type

Le typeof() d’une liste est list. is.list() permet de tester si l’objet est une liste quand as.list() permet la conversion en liste.

list(1:3)
#> [[1]]
#> [1] 1 2 3
as.list(1:3)
#> [[1]]
#> [1] 1
#> 
#> [[2]]
#> [1] 2
#> 
#> [[3]]
#> [1] 3

Matrices et Arrays

L’attribut dim permettait de passer d’un vecteur à une matrice ou à un array.
Dans le cas des listes, il permet de passer à des “matrice-liste” et “array-liste”.

l <- list(1:3, "a", TRUE, 1.0)
dim(l) <- c(2, 2)
l
#>      [,1]      [,2]
#> [1,] Integer,3 TRUE
#> [2,] "a"       1
l[[1, 1]]
#> [1] 1 2 3

Exercices

  1. Lister les points de divergences entre un vecteur et une liste.

  2. Pourquoi as.vector() ne fonctionne pas pour convertir une liste en vecteur ? Pourquoi l’usage de unlist() est nécessaire ?